const net = require('net');


class Request{
    constructor(options){
        this.method = options.method || "GET";
        this.host = options.host;
        this.port = options.port || 80;
        this.path = options.path || "/";
        this.body = options.body || {};
        this.headers = options.headers || {};
        if(!this.headers["Content-Type"]){
            this.headers["Content-Type"] = "application/x-www-form-urlencoded";
        }

        if(this.headers["Content-Type"] === "application/json"){
            this.bodyText = JSON.stringify(this.body);
        }else if(this.headers["Content-Type"] === "application/x-www-form-urlencoded"){
            this.bodyText = Object.keys(this.body).map(key => `${key}=${encodeURIComponent(this.body[key])}`).join('&');
        }

        this.headers["Content-Length"] = this.bodyText.length
    }

    send(connection){
        return new Promise((resolve , reject) => {
            const parser = new ResponsParser;
            if(connection){
                connection.write(this.toString());
            }else{
                connection = net.createConnection({
                    host: this.host,
                    port: this.port
                }, ()=>{
                    connection.write(this.toString());
                })

                connection.on('data',(data)=>{
                    console.log(data.toString());
                    parser.receive(data.toString());
                    if(parser.isFinished){
                        resolve(parser.response);
                        connection.end();
                    }
                });

                connection.on('error',(err) => {
                    reject(err);
                    connection.end();
                })
            }

        })
    }

    toString() {
        return `${this.method} ${this.path} HTTP/1.1\r\n${Object.keys(this.headers).map(key => `${key}: ${this.headers[key]}`).join('\r\n')}\r\n\n${this.bodyText}`;
    }
}

class ResponsParser {
    // 定义 parser 各种状态
    constructor(){
        this.WAITING_STATUS_LINE = 0;
        this.WAITING_STATUS_LINE_END = 1;
        this.WAITING_HEADER_NAME = 2;
        this.WAITING_HEADER_SPACE = 3;
        this.WAITING_HEADER_VALUE = 4;
        this.WAITING_HEADER_LINE_END = 5;
        this.WAITING_HEADER_BLOCK_END = 6;
        this.WAITING_BODY = 7;

        this.current = this.WAITING_STATUS_LINE;
        this.statusLine = "";
        this.headers = {};
        this.headerName = "";
        this.headerValue = "";
        // 用来解析 body 的 parser
        this.bodyParser = null;
    }

    get isFinished(){
        return this.bodyParser && this.bodyParser.isFinished;
    }

    get response(){
        this.statusLine.match(/HTTP\/1.1 ([0-9]+) ([\s\S]+)/)
        return {
            statusCode: RegExp.$1,
            statusText: RegExp.$2,
            headers: this.headers,
            body: this.bodyParser.content.join('')
        }
    }

    receive(string){
        for(let i = 0; i< string.length; i++){
            this.receiveChar(string.charAt(i));
        }
    }
    receiveChar(char){
        // 状态机解析字符串
        if(this.current === this.WAITING_STATUS_LINE){
            // 等待状态栏
            if(char === '\r'){
                // \r 状态栏接受结束
                this.current = this.WAITING_STATUS_LINE_END;
            }else{
                // 按照字符拼接
                this.statusLine += char;
            }
        }else if(this.current === this.WAITING_STATUS_LINE_END){
            // 状态栏接受完毕
            if(char === '\n'){
                this.current = this.WAITING_HEADER_NAME;
            }
        }else if(this.current === this.WAITING_HEADER_NAME){
            // 开始接受 header 的 name
            if(char === ':'){
                this.current = this.WAITING_HEADER_SPACE;
            }else if(char === '\r'){
                // 空行
                this.current = this.WAITING_HEADER_BLOCK_END
                // header 中标志 body 类型的字段，node 中是 chuncked
                // Transfer-Encoding: chunked
                if(this.headers["Transfer-Encoding"] === 'chunked'){
                    this.bodyParser = new TrunkedBodyParser();
                }
            }else {
                // 接受 header name
                this.headerName += char;
            }
        }else if(this.current === this.WAITING_HEADER_SPACE){
            // 开始接受 header 内容
            if(char === ' '){
                // 空格分隔 header 的 KV
                this.current = this.WAITING_HEADER_VALUE;
            }
        }else if(this.current === this.WAITING_HEADER_VALUE){
            // 接受 header 中的 value 部分
            if(char === '\r'){
                this.current = this.WAITING_HEADER_LINE_END;
                this.headers[this.headerName] = this.headerValue;
                this.headerName = "";
                this.headerValue = "";
            }else{
                this.headerValue += char;
            }
        }else if(this.current === this.WAITING_HEADER_LINE_END){
            // 一行header接受完毕，开始下一行
            if(char === '\n'){
                this.current = this.WAITING_HEADER_NAME;
            }
        }else if(this.current === this.WAITING_HEADER_BLOCK_END){
            // 全部 header 接受完毕，开始接受 body
            if(char === '\n'){
                this.current = this.WAITING_BODY;
            }
        }else if(this.current === this.WAITING_BODY){
            this.bodyParser.receiveChar(char);
        }
    }

}

class TrunkedBodyParser{
    constructor(){
        this.WAITING_LENGTH = 0;
        this.WAITING_LENGTH_LINE_END = 1;
        this.READING_TRUNK = 2;
        this.WAITING_NEW_LINE = 3;
        this.WAITING_NEW_LINE_END = 4;
        this.length = 0;
        this.content = [];
        this.isFinished = false;
        this.current = this.WAITING_LENGTH;
    }

    receiveChar(char){
        if(this.current === this.WAITING_LENGTH){
            if(char === '\r'){
                if(this.length === 0){
                    this.isFinished = true;
                }
                this.current = this.WAITING_LENGTH_LINE_END;
            }else{
                this.length *= 16;
                this.length += parseInt(char, 16);
            }
        }else if(this.current === this.WAITING_LENGTH_LINE_END){
            if(char === '\n'){
                this.current = this.READING_TRUNK;
            }
        }else if(this.current === this.READING_TRUNK){
            this.content.push(char);
            this.length --;
            if(this.length === 0){
                this.current = this.WAITING_NEW_LINE;
            }
        }else if(this.current === this.WAITING_NEW_LINE){
            if(char === '\r'){
                this.current = this.WAITING_NEW_LINE_END
            }
        }else if(this.current === this.WAITING_NEW_LINE_END){
            if(char === '\n'){
                this.current = this.WAITING_LENGTH;
            }
        }
    }
}



void async function (){
    let request = new Request({
        method: "POST",
        host: "127.0.0.1",
        port: "8088",
        path: "/",
        headers: {
            ["X-Foo2"]:"customed"
        },
        body:{
            name : "winter"
        }
    });

    let response = await request.send();

    console.log(response);
}();